media_pp\elements\source/
app_source.rs1use std::{sync::Arc, time::Duration};
2
3use crate::pp_log::{PpLog, pp_info};
4use crossbeam_channel::{Receiver, Sender, TrySendError, bounded, select};
5use thiserror::Error as ThisError;
6
7use crate::{
8 buffer::MediaBuffer,
9 bus::{Bus, BusEvent},
10 control::{
11 ControlMsg, ControlReceiver, RequestKind, apply_finish, apply_one, drain_control,
12 wait_out_pause,
13 },
14 element::{Element, ElementType, Source, SourceElement, element_pp_log},
15 error::Result,
16 pad::SrcPad,
17};
18
19#[derive(Debug, ThisError)]
22pub enum AppSourceError {
23 #[error("AppSource has already ended (its Pipeline finished, or Eos was already pushed)")]
24 Closed,
25}
26
27pub struct AppSource {
50 pp_log: PpLog,
51 name: Arc<str>,
52 pad: SrcPad,
53 data_rx: Receiver<MediaBuffer>,
54}
55
56#[derive(Clone)]
60pub struct AppSourceHandle {
61 name: Arc<str>,
62 data_tx: Sender<MediaBuffer>,
63}
64
65impl AppSource {
66 pub fn new(name: impl Into<String>, capacity: usize) -> (Self, AppSourceHandle) {
70 let name: Arc<str> = name.into().into();
71 let pp_log = element_pp_log(ElementType::AppSource, &name, None);
72 pp_info!(pp_log: &pp_log, "created: capacity={capacity}");
73 let pad = SrcPad::new(format!("{name}_src"));
74 let (data_tx, data_rx) = bounded(capacity);
75 (
76 Self {
77 name: name.clone(),
78 pp_log,
79 pad,
80 data_rx,
81 },
82 AppSourceHandle { name, data_tx },
83 )
84 }
85}
86
87impl AppSourceHandle {
88 pub fn name(&self) -> Arc<str> {
89 self.name.clone()
90 }
91
92 pub fn push(&self, buf: MediaBuffer) -> Result<()> {
95 self.data_tx
96 .send(buf)
97 .map_err(|_| AppSourceError::Closed.into())
98 }
99
100 pub fn try_push(&self, buf: MediaBuffer) -> Result<bool> {
106 match self.data_tx.try_send(buf) {
107 Ok(()) => Ok(true),
108 Err(TrySendError::Full(_)) => Ok(false),
109 Err(TrySendError::Disconnected(_)) => Err(AppSourceError::Closed.into()),
110 }
111 }
112}
113
114impl Element for AppSource {
115 fn name(&self) -> Arc<str> {
116 self.name.clone()
117 }
118
119 fn element_type(&self) -> ElementType {
120 ElementType::AppSource
121 }
122
123 fn pp_log(&self) -> &PpLog {
124 &self.pp_log
125 }
126
127 fn pp_log_mut(&mut self) -> &mut PpLog {
128 &mut self.pp_log
129 }
130}
131
132impl Source for AppSource {
133 fn src_pads(&mut self) -> &mut [SrcPad] {
134 std::slice::from_mut(&mut self.pad)
135 }
136}
137
138impl SourceElement for AppSource {
139 fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()> {
140 pp_info!(self, "started");
141 loop {
142 if drain_control(control, self, bus)?.stopped {
148 pp_info!(self, "stopped");
149 return Ok(());
150 }
151
152 select! {
153 recv(control.rx) -> req => {
154 match req {
155 Ok(req) => {
156 match req.kind {
157 RequestKind::Finish => {
158 apply_finish(self, bus, &req.ack);
159 pp_info!(self, "finished");
160 return Ok(());
161 }
162 RequestKind::Control(msg) => {
163 if apply_one(self, bus, msg, &req.ack)? {
164 pp_info!(self, "stopped");
165 return Ok(());
166 }
167 if msg == ControlMsg::Pause
168 && wait_out_pause(control, self, bus)?
169 {
170 pp_info!(self, "stopped");
171 return Ok(());
172 }
173 }
174 }
175 }
176 Err(_) => {
178 pp_info!(self, "run: control channel gone, ending");
179 return Ok(());
180 }
181 }
182 }
183 recv(self.data_rx) -> buf => {
184 match buf {
185 Ok(buf) if buf.is_eos() => {
186 pp_info!(self, "event=eos phase=source_received");
187 break;
188 }
189 Ok(buf) => {
190 if let Err(error) = self.pad.push(buf) {
191 bus.post(
192 &self.pp_log,
193 BusEvent::Error {
194 element_type: ElementType::AppSource,
195 name: self.name.clone(),
196 error,
197 },
198 );
199 }
200 }
201 Err(_) => {
203 pp_info!(self, "run: every AppSourceHandle dropped, ending");
204 break;
205 }
206 }
207 }
208 }
209 }
210 self.pad.push_eos(&self.pp_log)
211 }
212
213 fn seek(&mut self, target: Duration) -> Result<Duration> {
219 Ok(target)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use std::{
226 sync::atomic::{AtomicUsize, Ordering},
227 thread,
228 };
229
230 use super::*;
231 use crate::pipeline::Pipeline;
232
233 struct CountingSink {
234 pp_log: PpLog,
235 count: Arc<AtomicUsize>,
236 }
237
238 impl Element for CountingSink {
239 fn name(&self) -> Arc<str> {
240 "counter".into()
241 }
242
243 fn element_type(&self) -> ElementType {
244 ElementType::Other
245 }
246
247 fn pp_log(&self) -> &PpLog {
248 &self.pp_log
249 }
250
251 fn pp_log_mut(&mut self) -> &mut PpLog {
252 &mut self.pp_log
253 }
254 }
255
256 impl crate::element::Sink for CountingSink {
257 fn consume(&mut self, buf: MediaBuffer) -> Result<()> {
258 if !buf.is_eos() {
259 self.count.fetch_add(1, Ordering::SeqCst);
260 }
261 Ok(())
262 }
263
264 fn control(&mut self, _msg: ControlMsg) -> Result<()> {
265 Ok(())
266 }
267 }
268
269 fn packet() -> MediaBuffer {
270 MediaBuffer::Packet(Arc::new(ffmpeg_next::Packet::empty()))
271 }
272
273 fn wire(source: AppSource, count: Arc<AtomicUsize>) -> Arc<Pipeline> {
274 let sink = CountingSink {
275 count,
276 pp_log: element_pp_log(ElementType::Other, "counter", None),
277 };
278 Pipeline::new("test", source, |source, ctx| {
279 let branch = ctx.branch().to(Box::new(sink))?;
280 ctx.attach(source, 0, branch)?;
281 Ok(())
282 })
283 .expect("test pipeline wiring must succeed")
284 }
285
286 #[test]
287 fn pushed_buffers_reach_downstream_then_eos_ends_it() {
288 let (source, handle) = AppSource::new("app-source", 4);
289 let count = Arc::new(AtomicUsize::new(0));
290 let pipeline = wire(source, count.clone());
291 pipeline.run();
292
293 for _ in 0..5 {
294 handle.push(packet()).unwrap();
295 }
296 handle.push(MediaBuffer::Eos).unwrap();
297
298 let events: Vec<_> = pipeline.bus().iter().collect();
299 assert!(
300 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
301 "unexpected error event(s): {events:?}"
302 );
303 assert!(events.iter().any(|e| matches!(e, BusEvent::Eos { .. })));
304 assert_eq!(count.load(Ordering::SeqCst), 5);
305 }
306
307 #[test]
308 fn dropping_every_handle_without_eos_still_ends_cleanly() {
309 let (source, handle) = AppSource::new("app-source", 4);
310 let count = Arc::new(AtomicUsize::new(0));
311 let pipeline = wire(source, count.clone());
312 pipeline.run();
313
314 handle.push(packet()).unwrap();
315 handle.push(packet()).unwrap();
316 drop(handle); let events: Vec<_> = pipeline.bus().iter().collect();
319 assert!(
320 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
321 "unexpected error event(s): {events:?}"
322 );
323 assert!(events.iter().any(|e| matches!(e, BusEvent::Eos { .. })));
324 assert_eq!(count.load(Ordering::SeqCst), 2);
325 }
326
327 #[test]
333 fn stop_ends_promptly_even_with_no_producer() {
334 let (source, _handle) = AppSource::new("app-source", 4);
335 let count = Arc::new(AtomicUsize::new(0));
336 let pipeline = wire(source, count.clone());
337 pipeline.run();
338
339 thread::sleep(Duration::from_millis(50));
343 pipeline.stop();
344
345 let events: Vec<_> = pipeline.bus().iter().collect();
346 assert!(
347 !events.iter().any(|e| matches!(e, BusEvent::Error { .. })),
348 "unexpected error event(s): {events:?}"
349 );
350 assert_eq!(count.load(Ordering::SeqCst), 0);
351 }
352}